package com.uniovi.nmapgui.util;

import com.alibaba.fastjson.JSON;
import com.uniovi.nmapgui.nmap.entity.TaskIp;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.File;
import java.io.IOException;
import java.util.*;

public class JsoupManger {

    //jsoup 工具类   从xml中获取信息
    public static List<TaskIp> getMesFromHtml(String html, int taskId) {

        List<TaskIp> taskIps = new ArrayList<>();
        //***********************使用文件加载html文档
        //File html = new File(url);
        //将文件整理
        html.replace("\r", "").replace("\n", "");
        Document document2 = Jsoup.parse(html, "utf-8");
        Elements unhidden = document2.getElementsByClass("unhidden");
        Iterator<Element> it = unhidden.iterator();
        //System.out.println(document2.getElementsByClass("unhidden"));	// 获得div
        while (it.hasNext()) {
            TaskIp taskIp = new TaskIp();
            Element div = it.next();
            Elements tables = div.getElementsByTag("table");
            Elements osElement = div.getElementsByTag("li");
            String os = "";
            String ip = "";
            List<Map<String, String>> lists = new ArrayList<>();
            //System.out.println(os.size());
            //获得os
            for (int i = 0; i < osElement.size(); i++) {
                try {
                    if (osElement.get(i).ownText().contains("OS match:")) {

                        //解析一个相似度最高的  操作系统
                        os = osElement.get(i).getElementsByTag("b").get(0).ownText();
                        break;
                        //System.out.println(os);
                    }
                } catch (Exception e) {

                }
            }
            //获得 table
            for (int i = 0; i < tables.size(); i++) {

                Element table = tables.get(i);
                //System.out.println(table.id());
                if (table.id() != null && table.id().contains("porttable")) {
                    try {
                        Elements trs = table.getElementsByTag("tr");
                        //获取open
                        for (int j = 0; j < trs.size(); j++) {

                            if ("open".equals(trs.get(j).className()) || "filtered".equals(trs.get(j).className()) ||
                                    "closed".equals(trs.get(j).className()) || "unfiltered".equals(trs.get(j).className())) {

                                Map<String, String> map = new HashMap<>();
                                //解析每个接口状态
                                //System.out.println(trs.get(j).children().get(0).ownText());
                                map.put("port", trs.get(j).children().get(0).ownText());
                                map.put("type", trs.get(j).children().get(1).ownText());
                                map.put("state", trs.get(j).children().get(2).ownText());
                                map.put("service", trs.get(j).children().get(3).ownText());
                                map.put("reason", trs.get(j).children().get(4).ownText());
                                map.put("product", trs.get(j).children().get(5).ownText());
                                map.put("version", trs.get(j).children().get(6).ownText());
                                map.put("extrainfo", trs.get(j).children().get(7).ownText());
                                lists.add(map);
                            }
                        }
                        //获取ip
                        ip = table.id().replace("porttable_", "");
                        //System.out.println(ip);
                    } catch (Exception e) {
                        System.out.println("本次  解析出错");
                    }
                }
            }
            if (ip == null || "".equals(ip)) {

                continue;
            }
            taskIp.setOs(os);
            taskIp.setPort(JSON.toJSONString(lists));
            taskIp.setIp(ip);
            taskIp.setTaskId(taskId);
            taskIps.add(taskIp);
        }
        return taskIps;
        //***********************

        //***********************从String中加载HTML文档
       /* String html2 = "<html><head><title>Jsoup 标题</title></head>"
                + "<body><p>Parsed HTML into a doc.</p></body></html>";
        Document document3 = Jsoup.parse(html2);
        System.out.println(document3.title());	// 获得文档标题*/

        //***********************

    }

    //从txt中获取参数
    public static List<TaskIp> getMesFromText(String text, int taskId,String recordnewid) {

        List<TaskIp> taskIps = new ArrayList<>();

        //解析text字符串
        String[] ipMsgs = text.split("Nmap scan report for ");
        for (int i = 1; i < ipMsgs.length; i++) {

            TaskIp taskIp = new TaskIp();
            List<Map<String, Object>> ipMsgList = new ArrayList<>();
            String textMsg = ipMsgs[i];
            //获取ip
            String ip = StringUtils.substringBefore(textMsg, "\n").replace(" ", "").replace("localhost", "")
                    .replace("(", "").replace(")","");
            System.out.println(ip);
            taskIp.setIp(ip);
            taskIp.setRecordnewid(recordnewid);
            List<Map<String, Object>> portList = new ArrayList<>();
            //解析字符串中的端口与服务
            while (textMsg.contains("</span>")) {

                Map<String, Object> map = new HashMap<>();
                String ifHaveWarring = StringUtils.substringBefore(StringUtils.substringAfter(textMsg, "<span class"), "</span>");
                if (ifHaveWarring.contains("Warning") || ifHaveWarring.contains("WARNING")) {
                    //去除MAC Address 后面存在warring的情况
                    break;
                }
                try {
                    if (ifHaveWarring.contains("Not shown")) {

                        //去除类似<span class="filtered">Not shown: 998 filtered ports</span>的信息
                        continue;
                    }
                    String portString = StringUtils.substringBefore(StringUtils.substringAfter(textMsg, "<span class"), "</span>");
                    String[] stringArrays = StringUtils.substringAfter(portString, ">").split("\\s+");
                    //System.out.println(portString);
                    try {
                        String port = stringArrays[0].split("/")[0];
                        String type = stringArrays[0].split("/")[1];
                        //System.out.println(port+type);
                        if ("".equals(port) || "".equals(type)) {
                            continue;
                        }
                        map.put("port", port);
                        map.put("type", type);
                    } catch (Exception e) {
                    }
                    try {
                        String status = stringArrays[1];
                        map.put("status", status);
                        //System.out.println(status);
                    } catch (Exception e) {

                    }
                    try {
                        String service = stringArrays[2];
                        map.put("service", service);
                        //System.out.println(service);
                    } catch (Exception e) {
                    }
                    try {
                        String version = stringArrays[3];
                        map.put("version", version);
                        //System.out.println(version);
                    } catch (Exception e) {
                    }
                } catch (Exception e) {

                    e.printStackTrace();
                } finally {
                    //去除解析完成字符串信息
                    textMsg = StringUtils.substringAfter(textMsg, "</span>");
                }
                ipMsgList.add(map);
            }
            //mac地址
            if (textMsg.contains("MAC Address")) {

                //解析mac
                String macAddress = StringUtils.substringBefore(StringUtils.substringAfter(textMsg, "MAC Address:"), "(");
                textMsg = StringUtils.substringAfter(textMsg, macAddress);
                //解析厂商
                String vendor = StringUtils.substringBefore(textMsg, ")").replace("(", "").replace(")", "");
                textMsg = StringUtils.substringAfter(textMsg, ")");
                //System.out.println("MAC Address:"+macAddress+vendor);
                taskIp.setMac(macAddress);
                taskIp.setVendor(vendor);
            }
            //解析设备类型Device type
            if (textMsg.contains("Device type")) {

                //解析设备类型
                String deviceType = StringUtils.substringBefore(StringUtils.substringAfter(textMsg, "Device type: "), "\n");
                //System.out.println("deviceType:"+deviceType);
                taskIp.setDevicetype(deviceType);
            }
            //解析操作系统 Running
            if (textMsg.contains("Running")) {
                String os ="";
                //解析设备类型
                if(!textMsg.contains("JUST GUESSING")){
                    os = StringUtils.substringBefore(StringUtils.substringAfter(textMsg, "Running: "), "\n");
                }else {
                    os = StringUtils.substringBefore(StringUtils.substringAfter(textMsg, "Running (JUST GUESSING): "), "\n");
                }
                //System.out.println("os:"+os);
                taskIp.setOs(os);
            }
            taskIp.setPort(JSON.toJSONString(ipMsgList));
            taskIp.setTaskId(taskId);
            taskIps.add(taskIp);
        }
        return taskIps;
    }

    public static List<TaskIp> getMesFromText2(String text, int taskId,String recordnewid) {

        List<TaskIp> taskIps = new ArrayList<>();

        //解析text字符串
        String[] ipMsgs = text.split("Nmap scan report for ");
        for (int i = 1; i < ipMsgs.length; i++) {

            TaskIp taskIp = new TaskIp();
            List<Map<String, Object>> ipMsgList = new ArrayList<>();
            String textMsg = ipMsgs[i];
            //获取ip
            String ip = StringUtils.substringBefore(textMsg, "\n").replace(" ", "").replace("localhost", "")
                    .replace("(", "").replace(")","");
            System.out.println(ip);
            taskIp.setIp(ip);
            taskIp.setRecordnewid(recordnewid);
            List<Map<String, Object>> portList = new ArrayList<>();
            //解析字符串中的端口与服务
            if (textMsg.contains("8080/tcp")) {

                Map<String, Object> map = new HashMap<>();
                map.put("port", 8080);
                map.put("service", "tcp");
                ipMsgList.add(map);
            }
            if (textMsg.contains("80/tcp")) {

                Map<String, Object> map = new HashMap<>();
                map.put("port", 80);
                map.put("service", "tcp");
                ipMsgList.add(map);
            }
            if (textMsg.contains("443/tcp")) {

                Map<String, Object> map = new HashMap<>();
                map.put("port", 443);
                map.put("service", "tcp");
                ipMsgList.add(map);
            }
            //mac地址
            if (textMsg.contains("MAC Address")) {

                //解析mac
                String macAddress = StringUtils.substringBefore(StringUtils.substringAfter(textMsg, "MAC Address:"), "(");
                textMsg = StringUtils.substringAfter(textMsg, macAddress);
                //解析厂商
                String vendor = StringUtils.substringBefore(textMsg, ")").replace("(", "").replace(")", "");
                textMsg = StringUtils.substringAfter(textMsg, ")");
                //System.out.println("MAC Address:"+macAddress+vendor);
                taskIp.setMac(macAddress);
                taskIp.setVendor(vendor);
            }
            //解析设备类型Device type
            if (textMsg.contains("Device type")) {

                //解析设备类型
                String deviceType = StringUtils.substringBefore(StringUtils.substringAfter(textMsg, "Device type: "), "\n");
                //System.out.println("deviceType:"+deviceType);
                taskIp.setDevicetype(deviceType);
            }
            //解析操作系统 Running
            if (textMsg.contains("Running")) {
                String os ="";
                //解析设备类型
                if(!textMsg.contains("JUST GUESSING")){
                    os = StringUtils.substringBefore(StringUtils.substringAfter(textMsg, "Running: "), "\n");
                }else {
                    os = StringUtils.substringBefore(StringUtils.substringAfter(textMsg, "Running (JUST GUESSING): "), "\n");
                }
                //System.out.println("os:"+os);
                taskIp.setOs(os);
            }
            taskIp.setPort(JSON.toJSONString(ipMsgList));
            taskIp.setTaskId(taskId);
            taskIps.add(taskIp);
        }
        return taskIps;
    }
    public static void main(String[] args) {

        String text = "# Nmap 7.70 scan initiated Fri Jun 11 16:07:23 2021 as: nmap -sS -T4 -A -sC -oA /opt/log/c7657fcd-d5c3-4d47-be37-fa13ce41b61c -oX /tmp/nmap-scan_2021-06-11_16-07-22.xml --webxml www.bcmeter.cn\n" +
                "Warning: 118.212.149.84 giving up on port because retransmission cap hit (6).\n" +
                "Nmap scan report for www.bcmeter.cn (118.212.149.84)\n" +
                "Host is up (0.031s latency).\n" +
                "rDNS record for 118.212.149.84: 84.149.212.118.adsl-pool.jx.chinaunicom.com\n" +
                "Not shown: 980 closed ports\n" +
                "PORT     STATE    SERVICE         VERSION\n" +
                "80/tcp   open     http            nginx 1.17.2\n" +
                "| http-methods: \n" +
                "|_  Potentially risky methods: PUT DELETE TRACE PATCH\n" +
                "| http-robots.txt: 1 disallowed entry \n" +
                "|_/\n" +
                "|_http-server-header: nginx/1.17.2\n" +
                "| http-title: \\xE7\\x99\\xBE\\xE5\\xB7\\x9D\\xE8\\x87\\xAA\\xE6\\x9D\\xA5\\xE6\\xB0\\xB4\\xE6\\x94\\xB6\\xE8\\xB4\\xB9\\xE7\\xB3\\xBB\\xE7\\xBB\\x9F \\xE7\\x99\\xBB\\xE9\\x99\\x86\n" +
                "|_Requested resource was http://www.bcmeter.cn/a/login;JSESSIONID=e816337d84f744419eab6103145931e5\n" +
                "135/tcp  filtered msrpc\n" +
                "139/tcp  filtered netbios-ssn\n" +
                "306/tcp  open     mysql           MySQL 5.1.73\n" +
                "| mysql-info: \n" +
                "|   Protocol: 10\n" +
                "|   Version: 5.1.73\n" +
                "|   Thread ID: 26817\n" +
                "|   Capabilities flags: 63487\n" +
                "|   Some Capabilities: Support41Auth, SupportsCompression, ConnectWithDatabase, SupportsTransactions, LongPassword, LongColumnFlag, Speaks41ProtocolNew, Speaks41ProtocolOld, IgnoreSigpipes, FoundRows, IgnoreSpaceBeforeParenthesis, InteractiveClient, SupportsLoadDataLocal, ODBCClient, DontAllowDatabaseTableColumn\n" +
                "|   Status: Autocommit\n" +
                "|_  Salt: OEI!dU`aF{Y+hN.:wk4`\n" +
                "389/tcp  open     ssl/ldap?\n" +
                "445/tcp  filtered microsoft-ds\n" +
                "593/tcp  filtered http-rpc-epmap\n" +
                "2068/tcp open     ms-sql-s        Microsoft SQL Server 2012 11.00.2100; RTM\n" +
                "| ms-sql-ntlm-info: \n" +
                "|   Target_Name: WIN-RU03CB21QGA\n" +
                "|   NetBIOS_Domain_Name: WIN-RU03CB21QGA\n" +
                "|   NetBIOS_Computer_Name: WIN-RU03CB21QGA\n" +
                "|   DNS_Domain_Name: WIN-RU03CB21QGA\n" +
                "|   DNS_Computer_Name: WIN-RU03CB21QGA\n" +
                "|_  Product_Version: 6.1.7601\n" +
                "| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback\n" +
                "| Not valid before: 2020-02-24T08:14:26\n" +
                "|_Not valid after:  2050-02-24T08:14:26\n" +
                "|_ssl-date: 2021-06-11T08:10:40+00:00; +2s from scanner time.\n" +
                "3128/tcp filtered squid-http\n" +
                "4444/tcp filtered krb524\n" +
                "5001/tcp open     http            Apache Tomcat/Coyote JSP engine 1.1\n" +
                "|_http-server-header: Apache-Coyote/1.1\n" +
                "|_http-title: Site doesn't have a title.\n" +
                "5800/tcp filtered vnc-http\n" +
                "5900/tcp filtered vnc\n" +
                "6129/tcp filtered unknown\n" +
                "6543/tcp open     redis           Redis key-value store\n" +
                "6789/tcp open     ibm-db2-admin?\n" +
                "8001/tcp open     vcom-tunnel?\n" +
                "8002/tcp open     teradataordbms?\n" +
                "8899/tcp open     ospf-lite?\n" +
                "9003/tcp open     unknown\n" +
                "| fingerprint-strings: \n" +
                "|   SIPOptions: \n" +
                "|_    OK-\n" +
                "1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :\n" +
                "SF-Port9003-TCP:V=7.70%I=7%D=6/11%Time=60C31A1D%P=x86_64-redhat-linux-gnu%\n" +
                "SF:r(TLSSessionReq,9,\"OK\\x05\\t\\x10\\x0b\\x06\\xe5\\x07\")%r(SMBProgNeg,9,\"OK\\x0\n" +
                "SF:f\\t\\x10\\x0b\\x06\\xe5\\x07\")%r(SIPOptions,9,\"OK-\\t\\x10\\x0b\\x06\\xe5\\x07\")%r\n" +
                "SF:(WMSRequest,9,\"OK\\r\\n\\x10\\x0b\\x06\\xe5\\x07\");\n" +
                "Device type: general purpose|broadband router|WAP|printer\n" +
                "Running (JUST GUESSING): Microsoft Windows 7|2008|8.1 (94%), Asus embedded (91%), Linux 2.6.X|2.4.X (91%), Lexmark embedded (89%)\n" +
                "OS CPE: cpe:/o:microsoft:windows_7:::ultimate cpe:/o:microsoft:windows_server_2008:r2 cpe:/o:microsoft:windows_8.1 cpe:/h:asus:rt-ac66u cpe:/o:linux:linux_kernel:2.6 cpe:/h:asus:rt-n16 cpe:/h:lexmark:x644e cpe:/o:linux:linux_kernel:2.4\n" +
                "Aggressive OS guesses: Microsoft Windows 7 Ultimate (94%), Microsoft Windows Server 2008 R2 (92%), Microsoft Windows 8.1 Enterprise (91%), Asus RT-AC66U router (Linux 2.6) (91%), Asus RT-N16 WAP (Linux 2.6) (91%), Asus RT-N66U WAP (Linux 2.6) (91%), Tomato 1.28 (Linux 2.6.22) (91%), Linux 2.6.18 - 2.6.22 (90%), Linux 2.6.24 (90%), Microsoft Windows 7 SP1 or Windows Server 2008 (90%)\n" +
                "No exact OS matches for host (test conditions non-ideal).\n" +
                "Network Distance: 13 hops\n" +
                "Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows\n" +
                "\n" +
                "Host script results:\n" +
                "|_clock-skew: mean: 1s, deviation: 0s, median: 0s\n" +
                "\n" +
                "TRACEROUTE (using port 8080/tcp)\n" +
                "HOP RTT      ADDRESS\n" +
                "1   ...\n" +
                "2   6.09 ms  222.128.176.1\n" +
                "3   44.78 ms 61.148.163.57\n" +
                "4   10.68 ms 61.148.4.237\n" +
                "5   43.32 ms 61.49.214.25\n" +
                "6   34.95 ms 219.158.106.142\n" +
                "7   27.42 ms 130.132.212.118.adsl-pool.jx.chinaunicom.com (118.212.132.130)\n" +
                "8   27.42 ms 43.224.24.137\n" +
                "9   26.83 ms 43.224.24.134\n" +
                "10  ... 12\n" +
                "13  27.48 ms 84.149.212.118.adsl-pool.jx.chinaunicom.com (118.212.149.84)\n" +
                "\n" +
                "OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .\n" +
                "# Nmap done at Fri Jun 11 16:11:39 2021 -- 1 IP address (1 host up) scanned in 256.76 seconds\n";
        getMesFromText2(text, 1,"");
    }
}
